/**
 * 函数管理路由
 *
 * Created by snowingsea on 2020/03/02.
 */
const { Types } = require('mongoose');
const path = require('path');
const fs = require('fs-extra');
const middleware = require('./../middleware');
const functions = require('./../../models/functions');
const fileElements = require('./../../models/file-elements');
const tests = require('./../../models/tests');
const invokeRelations = require('./../../models/invoke-relations');
const PhoenixError = require('./../../models/phoenix-error');
const utility = require('./../../models/utility');
const ProjectVersion = require('../../models/mongo/project-version');
const ProjectVersionModel = require('../../models/project-versions');
const FunctionVariable = require('../../models/mongo/function-variable');
const FileGlobalVariable = require('../../models/mongo/file-global-variable');
const handleIntegrationVariables = require('../../models/handle-integration-variables');
const codeInstrumentations = require('../../models/code-instrumentation');
const logger = require('../../models/logger');

/**
 * 获取函数信息
 * @param req
 * @param res
 * @param next
 */
function getFunction(req, res, next) { // eslint-disable-line no-unused-vars
  functions.updateUnread(req.params.functionId, false)
    .then(() => functions.getFunction(req.params.functionId))
    .then((func) => {
      res.json(fileElements.getJson(func));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 编辑函数信息
 * @param req
 * @param res
 * @param next
 */
function updateFunction(req, res, next) {
  functions.updateFunction(req.params.functionId, Object.assign(req.query, req.body))
    .then(() => functions.getFunction(req.params.functionId))
    .then((func) => {
      res.json(fileElements.getJson(func));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 批量编辑函数信息
 * @param req
 * @param res
 * @param next
 */
function updateFunctions(req, res, next) {
  const { projectVersionId } = req.params;
  let fileIds;
  if (utility.isEmpty(req.query.functionIds)) {
    fileIds = req.$compiledFiles.map(({ _id }) => _id);
  }
  functions.getFunctions(projectVersionId, req.query, fileIds)
    .then((resFunctions) => functions.updateFunctions(resFunctions, req.query))
    .then(() => {
      res.json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取函数列表
 * @param req
 * @param res
 * @param next
 */
function getFunctions(req, res, next) {
  const resFunctions = {
    pagination: req.filter,
  };
  functions.filter(req.params.fileId, req.filter, req.query)
    .then((data) => {
      resFunctions.functions = data.map((func) => fileElements.getSummaryJson(func));
      resFunctions.pagination.total = data.length;
      res.json(resFunctions);
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取函数CFG
 * @param req
 * @param res
 * @param next
 */
function getFunctionCFG(req, res, next) { // eslint-disable-line no-unused-vars
  return res.json(functions.getCFGJson(req.$functionCFG));
}

/**
 * 获取函数变量信息
 * @param req
 * @param res
 * @param next
 */
function getFunctionVariables(req, res, next) { // eslint-disable-line no-unused-vars
  (async () => {
    const { $functionVariables, $projectVersion } = req;
    const { versionType } = $projectVersion;
    const { functionId } = $functionVariables;
    let funcVariables = await functions.getFunctionVariableJson($functionVariables);
    funcVariables.mangledId = new Set();
    // 处理集成测试variables
    if (versionType === ProjectVersionModel.versionType.integrationTest) {
      funcVariables = await functions.getRelationFuncsVariables(functionId);
    }
    const func = await functions.getFunction(functionId);
    // 参与集成的函数 fileId_mangledId
    funcVariables.mangledId.add(`${func.fileId}_${func.mangledId}`);
    funcVariables.mangledId = [...funcVariables.mangledId];
    // 去除没有返回值的空结构
    if (funcVariables.output && funcVariables.output['%'] && Object.keys(funcVariables.output['%']).length === 0) {
      delete funcVariables.output['%'];
    }
    res.json(funcVariables);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 设置全局变量输出检查项
 * @param req
 * @param res
 * @param next
 */
function addGlobalOutput(req, res, next) {
  (async () => {
    let { variableName, fileId } = req.query;
    const content = {};
    let variableInfo;
    const { versionType } = req.$projectVersion;
    if (!variableName) {
      next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
      return;
    }
    const splitVariable = handleIntegrationVariables.checkAttachFileIdOrFunctionId(variableName);
    if (splitVariable) {
      // eslint-disable-next-line prefer-destructuring
      fileId = splitVariable[1];
      variableName = variableName.replace(splitVariable[0], '');
    }
    let variableNameExist = true;
    if (!req.$functionVariables.variables
      || !req.$functionVariables.variables.global
      || !req.$functionVariables.variables.global[variableName]) {
      variableNameExist = false;
    }
    if (versionType === ProjectVersionModel.versionType.integrationTest) {
      if (variableNameExist) {
        variableInfo = req.$functionVariables.variables.global[variableName];
      } else {
        const fileGlobals = await FileGlobalVariable.aggregate([{
          $match: {
            fileId: Types.ObjectId(fileId),
            [`globals.${variableName}`]: { $exists: true },
          },
        },
        {
          $project: {
            [`globals.${variableName}.@attributes`]: 1,
            [`globals.${variableName}.@type`]: 1,
          },
        },
        ]);
        if (fileGlobals.length > 0) {
          variableInfo = fileGlobals[0].globals[variableName];
          // 来自于其它文件的静态全局变量需要拼接来源文件的文件id
          if (variableInfo['@attributes'].includes('isStatic') && fileId !== req.$file._id.toString()) {
            variableName = `${variableName}@${fileId}`;
          }
        } else {
          next(new PhoenixError('not found', `Not found, global variables[${variableName}] not found`));
          return;
        }
      }
    } else {
      if (!variableNameExist) {
        next(new PhoenixError('not found', `Not found, global variables[${variableName}] not found`));
        return;
      }
      variableInfo = req.$functionVariables.variables.global[variableName];
    }
    await functions.addOutputGlobalVariable(req.params.functionId,
      variableName, variableInfo, fileId);
    content[variableName] = variableInfo;
    await functions.removeResultOfExecution(req.params.functionId);
    res.json(content);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 设置绝对地址输出检查项
 * @param req
 * @param res
 * @param next
 */
function addFixedAddressOutput(req, res, next) {
  (async () => {
    const variableName = functions.formatFixedAddressName(req.query.variableName);
    const content = {};
    if (!variableName) {
      next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
      return;
    }
    if (!req.$functionVariables
      || !req.$functionVariables.fixedAddrs
      || !req.$functionVariables.fixedAddrs.bases[variableName]) {
      next(new PhoenixError('not found', `Not found, fixed address variables[${variableName}] not found`));
      return;
    }
    const variableInfo = req.$functionVariables.fixedAddrs.bases[variableName];
    await functions.addOutputFixedAddress(req.params.functionId, variableName, variableInfo);
    content[variableName] = variableInfo;
    await functions.removeResultOfExecution(req.params.functionId);
    res.json(content);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 设置静态变量输出检查项
 * @param req
 * @param res
 * @param next
 */
function addStaticsOutputVariable(req, res, next) {
  (async () => {
    const { index } = req.query;
    if (!index) {
      next(new PhoenixError('invalid request', 'Missing parameters. "index" is required'));
      return;
    }
    let newIndex = index;
    const { versionType } = req.$projectVersion;
    let { variables } = req.$functionVariables;
    // 集成测试需要重新组建variable
    if (versionType === ProjectVersionModel.versionType.integrationTest) {
      const { functionId } = req.$functionVariables;
      const inputStatics = await functions.handleIntegrationStaticsOutput(functionId);
      if (!variables) {
        variables = {};
      }
      variables.statics = inputStatics;
      newIndex = handleIntegrationVariables.handleStaticsOutputFunctionId(functionId, index);
    }
    if (!variables
      || !variables.statics
      || !variables.statics[index]) {
      next(new PhoenixError('not found', `Not found, statics index [${index}] not found`));
      return;
    }
    const variableInfo = req.$functionVariables.variables.statics[index];
    await functions.addOutputStaticsVariable(req.params.functionId, newIndex, variableInfo);
    const content = {};
    content[index] = variableInfo;
    await functions.removeResultOfExecution(req.params.functionId);
    res.json(content);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 取消设置静态变量检查项
 * @param req
 * @param res
 * @param next
 */
function removeStaticsOutputVariable(req, res, next) {
  const { index } = req.params;
  const { functionId } = req.params;
  if (!index) {
    next(new PhoenixError('invalid request', 'Missing parameters. "index" is required'));
    return;
  }
  functions.removeOutputStaticsVariable(functionId, index)
    .then(() => functions.removeResultOfExecution(functionId))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 取消设置全局变量检查项
 * @param req
 * @param res
 * @param next
 */
function removeGlobalOutputVariable(req, res, next) {
  const { variableName, functionId } = req.params;
  if (!variableName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
    return;
  }
  functions.removeOutputGlobalVariable(functionId, variableName)
    .then(() => functions.removeResultOfExecution(functionId))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 设置指针目标输出检查项
 * @param req
 * @param res
 * @param next
 */
function addMallocOutput(req, res, next) {
  const { variableName } = req.query;
  if (!variableName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
    return;
  }
  if (!req.$functionVariables.malloc || !req.$functionVariables.malloc[variableName]) {
    next(new PhoenixError('not found', `Not found, malloc variables[${variableName}] not found`));
    return;
  }
  const variableInfo = req.$functionVariables.malloc[variableName];
  functions.addOutputMallocVariable(req.params.functionId, variableName, variableInfo)
    .then(() => functions.removeResultOfExecution(req.params.functionId))
    .then(() => {
      const content = {};
      content[variableName] = variableInfo;
      res.json(content);
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 取消设置指针目标检查项
 * @param req
 * @param res
 * @param next
 */
function removeMallocOutputVariable(req, res, next) {
  // eslint-disable-next-line prefer-const
  let { variableName, functionId } = req.params;
  if (!variableName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
    return;
  }
  if (handleIntegrationVariables.checkAttachFileIdOrFunctionId(variableName)) {
    variableName = variableName.replace(handleIntegrationVariables.checkAttachFileIdOrFunctionId(variableName)[0], '');
  }
  functions.removeOutputMallocVariable(functionId, variableName)
    .then(() => functions.removeResultOfExecution(functionId))
    .then()
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 设置成员函数所属类检查项
 * @param req
 * @param res
 * @param next
 */
function addObjectOutput(req, res, next) {
  functions.addOutputObjectVariable(req.params.functionId)
    .then(() => functions.removeResultOfExecution(req.params.functionId))
    .then(() => {
      res.json({});
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 取消成员函数所属类检查项
 * @param req
 * @param res
 * @param next
 */
function removeObjectOutputVariable(req, res, next) {
  const { functionId } = req.params;
  functions.removeOutputObjectVariable(functionId)
    .then(() => functions.removeResultOfExecution(functionId))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 取消绝对地址检查项
 * @param req
 * @param res
 * @param next
 */
function removeFixedAddressOutput(req, res, next) {
  const { functionId } = req.params;
  const variableName = functions.formatFixedAddressName(req.params.variableName);
  if (!variableName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
    return;
  }
  functions.removeOutputFixedAddress(functionId, variableName)
    .then(() => functions.removeResultOfExecution(functionId))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 添加指针目标
 * @param req
 * @param res
 * @param next
 */
function addMallocVariable(req, res, next) {
  const {
    elementTypeName,
    variableName,
    typeName,
    length,
  } = req.body;
  if (!variableName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "variableName" is required'));
    return;
  }
  if (!typeName && !elementTypeName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "typeName" or "elementTypeName" is required'));
    return;
  }
  if ((elementTypeName && !length) || (!elementTypeName && length)) {
    next(new PhoenixError('invalid request', 'Missing parameters. "elementTypeName" or "length" is required'));
    return;
  }
  if (req.$projectVersion.versionType === ProjectVersionModel.versionType.integrationTest && !req.body.fileId) {
    next(new PhoenixError('invalid request', 'Missing parameters. "fileId" is required'));
    return;
  }
  const { functionId } = req.params;
  functions.addMallocVariable(functionId, req.body)
    .then(() => functions.getMallocVariable(functionId, variableName))
    .then((variable) => {
      res.json(functions.getMallocVariableJson(functionId, variableName, variable));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取指针目标信息
 * @param req
 * @param res
 * @param next
 */
function getMallocVariable(req, res, next) { // eslint-disable-line no-unused-vars
  const { variableName, functionId } = req.params;
  res.json(functions.getMallocVariableJson(functionId, variableName, req.$mallocVariable));
}

/**
 * 删除指针目标信息
 * @param req
 * @param res
 * @param next
 */
function removeMallocVariable(req, res, next) {
  functions.removeMallocVariable(req.params.functionId, req.params.variableName)
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 对传入的数组类型参数检查
 * @param {Object} originalMessage 原始数组类型信息
 * @param typeName 新类型信息
 * @param elementTypeName 新数组元素类型信息
 * @param length 新数组长度信息
 * @returns {Promise}
 */
function checkParams(originalMessage, { typeName, elementTypeName, length }) {
  const oldIsArray = originalMessage['@elementType'];
  const newIsArray = elementTypeName || length || (!typeName && oldIsArray);
  if (!oldIsArray && newIsArray && !(elementTypeName && length)) {
    return Promise.reject(new PhoenixError('invalid request',
      'Missing parameters. "elementTypeName" and "length" are required'));
  }
  return Promise.resolve();
}

/**
 * 编辑指针目标
 * @param req
 * @param res
 * @param next
 */
function updateMallocVariable(req, res, next) {
  if (req.params.variableName === req.body.variableName) {
    delete req.body.variableName;
  }
  const { functionId } = req.params;
  req.params.variableName = utility.trim(req.params.variableName);
  const newVariableName = req.body.variableName || req.params.variableName;
  if (req.$projectVersion.versionType === ProjectVersionModel.versionType.integrationTest && !req.body.fileId) {
    next(new PhoenixError('invalid request', 'Missing parameters. "fileId" is required'));
    return;
  }
  checkParams(req.$mallocVariable, req.body)
    .then(() => {
      const { $mallocVariable } = req;
      const originName = req.params.variableName;
      return functions.updateMallocVariable(functionId, originName, req.body, $mallocVariable);
    })
    .then(() => functions.getMallocVariable(functionId, newVariableName))
    .then((variable) => {
      res.json(functions.getMallocVariableJson(functionId, newVariableName, variable));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 添加桩函数
 * @param req
 * @param res
 * @param next
 */
function addStub(req, res, next) {
  const { stubName } = req.query;
  if (!stubName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "stubName" is required'));
    return;
  }
  if (!req.query.paramNames) {
    req.query.paramNames = [];
  } else if (!utility.isArrayType(req.query.paramNames)) {
    req.query.paramNames = [req.query.paramNames];
  }
  if (!req.query.paramTypeNames) {
    req.query.paramTypeNames = [];
  } else if (!utility.isArrayType(req.query.paramTypeNames)) {
    req.query.paramTypeNames = [req.query.paramTypeNames];
  }
  if (req.query.paramNames.length > req.query.paramTypeNames.length) {
    next(new PhoenixError('invalid request', '"paramTypeNames" should not less then "paramNames"'));
    return;
  }
  const { functionId } = req.params;
  const { times, defaultKind, defaultTimes } = req.query;
  req.query.times = times ? parseInt(times, 10) : 0;
  req.query.defaultTimes = defaultTimes ? parseInt(defaultTimes, 10) : 0;
  req.query.defaultKind = defaultKind ? parseInt(defaultKind, 10) : tests.stubKind.value;
  functions.addStub(functionId, req.query)
    .then(() => functions.getStub(functionId, stubName))
    .then((target) => {
      res.json(functions.getStubJson(functionId, stubName, target));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取桩函数信息
 * @param req
 * @param res
 */
function getStub(req, res) {
  const { stubName, functionId } = req.params;
  res.json(functions.getStubJson(functionId, stubName, req.$stub));
}

/**
 * 删除桩函数
 * @param req
 * @param res
 * @param next
 */
function removeStub(req, res, next) {
  const { functionId, stubName } = req.params;
  functions.removeStub(functionId, stubName)
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 编辑桩函数
 * @param req
 * @param res
 * @param next
 */
function updateStub(req, res, next) {
  if (req.params.stubName === req.query.newStubName) {
    delete req.query.newStubName;
  }
  const { stubName, functionId } = req.params;
  if (req.query.paramNames) {
    if (!utility.isArrayType(req.query.paramNames)) {
      req.query.paramNames = [req.query.paramNames];
    }
    if (req.query.paramNames.length !== req.$stub.params.length) {
      next(new PhoenixError('invalid request',
        'When paramNames exist, the length of them should be same as the length of paramTypeNames'));
      return;
    }
  }
  const newStubName = req.query.newStubName || req.params.stubName;
  if (req.query.times !== undefined) {
    req.query.times = parseInt(req.query.times.toString(), 10);
  }
  if (req.query.defaultTimes !== undefined) {
    req.query.defaultTimes = parseInt(req.query.defaultTimes.toString(), 10);
  }
  if (req.query.defaultKind !== undefined) {
    req.query.defaultKind = parseInt(req.query.defaultKind.toString(), 10);
  }
  functions.updateStub(functionId, stubName, req.$stub, req.query)
    .then(() => functions.getStub(functionId, newStubName))
    .then((stub) => {
      res.json(functions.getStubJson(functionId, newStubName, stub));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 添加桩函数指针目标
 * @param req
 * @param res
 * @param next
 */
function addStubPointerTarget(req, res, next) {
  req.query.pointerTargetName = utility.trim(req.query.pointerTargetName);
  req.query.elementTypeName = utility.trim(req.query.elementTypeName);
  req.query.typeName = utility.trim(req.query.typeName);
  req.query.versionType = req.$projectVersion.versionType;
  Object.assign(req.query, req.body);
  const {
    pointerTargetName,
    typeName,
    elementTypeName,
    length,
  } = req.query;
  if (!pointerTargetName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "pointerTargetName" is required'));
    return;
  }
  if (!typeName && !elementTypeName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "typeName" or "elementTypeName" is required'));
    return;
  }
  if ((elementTypeName && !length) || (!elementTypeName && length)) {
    next(new PhoenixError('invalid request', 'Missing parameters. "elementTypeName" or "length" is required'));
    return;
  }

  const { functionId, stubName } = req.params;
  functions.getStubPointerTarget(functionId, stubName, pointerTargetName)
    .then((pointerTarget) => {
      if (pointerTarget) {
        return Promise.reject(new PhoenixError('conflict', 'Stub pointerTarget is exists'));
      }
      return functions.addStubPointerTarget(functionId, stubName, req.query);
    })
    .then(() => functions.getStubPointerTarget(functionId, stubName, pointerTargetName))
    .then((target) => {
      res.json(functions.getStubPointerTargetJson(functionId, stubName, pointerTargetName, target));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 添加绝对地址
 * @param req
 * @param res
 * @param next
 */
function addFixedAddress(req, res, next) {
  const { length, fileId, assignmentKind } = req.body;
  const fixedAddressName = functions.formatFixedAddressName(req.body.fixedAddressName);
  if (!fixedAddressName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "fixedAddressName" is required'));
    return;
  }
  if (!assignmentKind) {
    next(new PhoenixError('invalid request', 'Missing parameters. "assignmentKind" is required'));
    return;
  }

  const { functionId } = req.params;
  functions.getFixedAddress(functionId, fixedAddressName)
    .then((address) => {
      if (address) {
        return Promise.reject(new PhoenixError('conflict', 'fixed address is exists'));
      }
      return functions.addFixedAddressBases(
        functionId,
        fixedAddressName,
        length,
        req.$pointerTargets,
        fileId,
        assignmentKind
      );
    })
    .then(() => functions.getFixedAddress(functionId, fixedAddressName))
    .then((address) => {
      res.json(functions.getFixedAddressJson(functionId, fixedAddressName, address));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取桩函数指针目标信息
 * @param req
 * @param res
 * @param next
 */
function getStubPointerTarget(req, res, next) { // eslint-disable-line no-unused-vars
  const { functionId, stubName, pointerTargetName } = req.$stubPointerTargetParams;
  const target = req.$stubPointerTarget;
  res.json(functions.getStubPointerTargetJson(functionId, stubName, pointerTargetName, target));
}

/**
 * 获取绝对地址信息
 * @param req
 * @param res
 * @param next
 */
function getFixedAddress(req, res, next) { // eslint-disable-line no-unused-vars
  const { functionId, fixedAddressName } = req.params;
  res.json(functions.getFixedAddressJson(functionId, fixedAddressName, req.$fixedAddressBase));
}

/**
 * 删除桩函数指针目标信息
 * @param req
 * @param res
 * @param next
 */
function removeStubPointerTarget(req, res, next) {
  const { functionId, stubName, pointerTargetName } = req.$stubPointerTargetParams;
  functions.removeStubPointerTarget(functionId, stubName, pointerTargetName)
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 删除绝对地址
 * @param req
 * @param res
 * @param next
 */
function removeFixedAddress(req, res, next) {
  functions.removeFixedAddress(
    req.params.functionId,
    req.params.fixedAddressName
  )
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 编辑桩函数指针目标
 * @param req
 * @param res
 * @param next
 */
function updateStubPointerTarget(req, res, next) {
  req.query.pointerTargetName = utility.trim(req.query.pointerTargetName);
  const { functionId, stubName, pointerTargetName } = req.$stubPointerTargetParams;
  if (pointerTargetName === req.query.pointerTargetName) {
    delete req.query.pointerTargetName;
  }
  const newTargetName = req.query.pointerTargetName || pointerTargetName;
  Promise.resolve()
    .then(() => checkParams(req.$stubPointerTarget, req.query))
    .then(() => {
      if (req.query.pointerTargetName) {
        return functions.getStubPointerTarget(functionId, stubName, req.query.pointerTargetName);
      }
      return Promise.resolve();
    })
    .then((pointerTarget) => {
      if (pointerTarget) {
        return Promise.reject(new PhoenixError('conflict', 'stub pointer target is exists'));
      }
      const originName = pointerTargetName;
      const target = req.$stubPointerTarget;
      return functions.updateStubPointerTarget(functionId, stubName, originName, req.query, target);
    })
    .then(() => functions.getStubPointerTarget(functionId, stubName, newTargetName))
    .then((target) => {
      res.json(functions.getStubPointerTargetJson(functionId, stubName, newTargetName, target));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 编辑绝对地址
 * @param req
 * @param res
 * @param next
 */
function updateFixedAddress(req, res, next) {
  const { functionId } = req.params;
  const { length, testCaseId, assignmentKind } = req.body;
  if (!testCaseId) {
    next(new PhoenixError('invalid request', 'Missing parameters. "testCaseId" is required'));
    return;
  }
  if (!assignmentKind) {
    next(new PhoenixError('invalid request', 'Missing parameters. "assignmentKind" is required'));
    return;
  }
  const originName = functions.formatFixedAddressName(req.params.fixedAddressName);
  const newName = functions.formatFixedAddressName(req.body.newName);
  let fixedAddressName;
  functions.getFixedAddress(functionId, newName)
    .then((address) => {
      if (address && newName !== originName) {
        return Promise.reject(new PhoenixError('conflict', 'fixed address is exists'));
      }
      return functions.updateFixedAddress(
        functionId,
        originName,
        newName,
        req.$pointerTargets,
        length,
        testCaseId,
        assignmentKind
      );
    })
    .then(() => {
      fixedAddressName = newName || originName;
      return functions.getFixedAddress(functionId, fixedAddressName);
    })
    .then((address) => {
      res.json(functions.getFixedAddressJson(functionId, fixedAddressName, address));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 项目总览-函数列表
 * @param req
 * @param res
 * @param next
 */
function allFunctionsOverview(req, res, next) {
  (async () => {
    const { projectVersionId: versionId } = req.params;
    const {
      sortBy, order, fileId, resultKind, changed, tested,
    } = req.query;
    let { page, perPage } = req.query;
    page = parseInt(page, 10) || 1;
    perPage = parseInt(perPage, 10) || 100;
    const version = await ProjectVersion.findById(Types.ObjectId(versionId), [
      'projectId', 'versionName', 'coverages', 'oldVersionId',
    ], { lean: true });
    const [list, total, funcResultStatistic] = await functions.getOverview(versionId, {
      fileId,
      page,
      pageSize: perPage,
      sortBy,
      order,
      resKind: resultKind,
      changed,
      tested: tested ? tested === 'true' || tested === '1' : undefined,
    });
    version.funcResultStatistic = funcResultStatistic;
    version.projectName = req.$project.projectName;
    res.json({
      version,
      functions: list,
      pagination: {
        total,
        page,
        perPage,
        sortBy,
        order,
      },
    });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 项目总览-函数列表下载
 * @param req
 * @param res
 * @param next
 */
function exportFunctionsOverview(req, res, next) {
  (async () => {
    const { projectVersionId: versionId } = req.params;
    let {
      tested,
    } = req.query;
    tested = tested ? tested === 'true' || tested === '1' : undefined;
    const excelName = req.$project.projectName.concat(' ').concat(req.$projectVersion.versionName).concat('.函数列表.xlsx');
    const [xlsxFilePath, cachePath] = await functions.generateOverviewXlsx(versionId, req.$projectVersion.coverages, excelName, req.$locale, tested);
    res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition');
    res.download(xlsxFilePath, encodeURI(path.basename(xlsxFilePath)), () => fs.remove(cachePath));
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取可手动添加绝对地址表达式列表
 * @param req
 * @param res
 * @param next
 */
function getFixedAddressExprs(req, res, next) { // eslint-disable-line no-unused-vars
  res.json(functions.getUnusedFixedAddresses(req.$functionVariables));
}

/**
 * 手动添加绝对地址
 * @param req
 * @param res
 * @param next
 */
function addFixedAddressExprs(req, res, next) {
  const { exprsName } = req.body;
  const { functionId } = req.params;
  if (!exprsName) {
    next(new PhoenixError('invalid request', 'Missing parameters. "exprsName" is required'));
    return;
  }
  functions.addFixedAddressExprs(functionId, exprsName)
    .then(() => tests.addFixedAddressDefaultValue(functionId, exprsName, req.$functionVariables))
    .then(() => functions.removeResultOfExecution(functionId))// 清除函数执行结果
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 删除手动添加的绝对地址
 * @param req
 * @param res
 * @param next
 */
function removeFixedAddressExpr(req, res, next) {
  const { functionId, exprName } = req.params;
  functions.removeFixedAddressExpr(functionId, exprName)
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function updateStubStatus(req, res, next) {
  const { functionId } = req.params;
  const {
    stubStatus,
    functionId: toFuncId,
    mangledId,
    functionName,
  } = req.body;
  invokeRelations.updateStubStatus(functionId, toFuncId, mangledId, functionName, stubStatus)
    .then(() => functions.updateInvokeCoverageTotal([functionId], req.$projectVersion._id))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getFuncInvokes(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const result = await functions.integrationSolution(functionId, req.$projectVersion, false, false);
    res.json(result);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function getFuncInvokeFiles(req, res, next) {
  (async () => {
    const { mangledId, projectVersionId } = req.params;
    const files = await functions.getFuncInvokeFiles(projectVersionId, mangledId);
    res.json({ files });
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
// 获取外部变量可选list
function getExternalGlobals(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const {
      q,
    } = req.query;
    const list = await functions.getExternalGLobalOptionsList(functionId, {
      q,
    });
    const { externalGlobals: selected } = await FunctionVariable
      .findOne({ functionId: Types.ObjectId(functionId) });
    res.json({
      globals: list.map((item) => ({
        ...item,
        selected: !!selected.find(({ fullname, fileId }) => fullname === item.fullname
          && fileId.toString() === item.fileId.toString()),
      })),
    });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function addExternalGlobals(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { globals } = req.body;
    if (!globals) {
      throw new PhoenixError('invalid request', 'need globals');
    }
    await functions.replaceExternalGlobals(functionId, globals);
    res.status(204).json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function updateInvokeFile(req, res, next) {
  const { functionId, mangledId } = req.params;
  const { originalFileId, fileId } = req.body;
  invokeRelations.updateInvokeFile(
    functionId,
    mangledId,
    originalFileId,
    fileId,
    req.$projectVersion._id.toString()
  )
    .then(() => functions.integrationUpdateTestCaseStubs(functionId, [], mangledId))// 更新测试用例中的stubs
    .then(() => functions.removeResultOfExecution(functionId))
    .then(() => {
      res.status(204).json();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function invokeGraph(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const edges = await functions.invokeGraph(functionId);
    res.json({ edges });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function getInvokeChildren(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { currentFunctionId } = req.query;
    const { _id: versionId } = req.$projectVersion;
    const invokeFuncDepth = currentFunctionId ? 1 : 0;
    const includeCurrentFunc = !currentFunctionId;
    const tree = await functions.getInvokeChildren(
      functionId,
      currentFunctionId,
      versionId,
      invokeFuncDepth,
      includeCurrentFunc
    );
    res.json(tree);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getTestCallExprs(req, res, next) {
  (async () => {
    let { prevNodes, testIds, fileId } = req.body;
    const { mangledId, callexprId } = req.body;
    prevNodes = prevNodes.map(Types.ObjectId);
    testIds = testIds ? testIds.map(Types.ObjectId) : undefined;
    fileId = Types.ObjectId(fileId);
    const ret = await functions.callExprTimes(prevNodes, testIds, fileId, mangledId, callexprId);
    res.json(ret);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function updateAllRelationStubStatusByFunctionId(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { stubStatus, depth } = req.body;
    const { _id: versionId } = req.$projectVersion;
    // const funcs = await functions.getFunctions(versionId, { kinds: [fileElements.elementKind.specialFunction] });
    // const specialFunctionIds = new Set();
    // funcs.forEach((func) => {
    //   specialFunctionIds.add(func._id.toString());
    // });
    await functions.updateAllRelationStubStatusByFunctionId(functionId, versionId, stubStatus, depth);
    await functions.updateInvokeCoverageTotal([functionId], versionId);
    await functions.integrationUpdateTestCaseStubs(functionId);
    res.status(204).json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function getIntegrationFixedAddressExprs(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const resJson = await functions.getIntegrationFixedAddressExprs(
      functionId,
      req.$projectVersion._id
    );
    res.json(resJson);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function saveIntegrationFixedAddressExprs(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    await functions.saveIntegrationFixedAddressExprs(
      functionId,
      req.$projectVersion._id,
      req.body
    );
    res.json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function getIntegrationFixedAddress(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const resJson = await functions.getIntegrationFixedAddress(
      functionId,
      req.$file._id,
      req.$projectVersion._id,
    );
    res.json(resJson);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getInvokeCoveredLocations(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { invokeChain } = req.body;
    const resJson = await functions.getInvokeCoveredLocations(
      functionId,
      invokeChain,
    );
    res.json(resJson);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function addIntegratedFuncPointerTarget(req, res, next) {
  (async () => {
    const { functionId, mangledId } = req.params;
    const {
      pointerTargetName,
      typeName,
      elementTypeName,
      length,
    } = req.body;
    if (!pointerTargetName) {
      throw new PhoenixError('invalid request', 'Missing parameters. "pointerTargetName" is required');
    }
    if (!typeName && !elementTypeName) {
      throw new PhoenixError('invalid request', 'Missing parameters. "typeName" or "elementTypeName" is required');
    }
    if ((elementTypeName && !length) || (!elementTypeName && length)) {
      throw new PhoenixError('invalid request', 'Missing parameters. "elementTypeName" or "length" is required');
    }
    let pointerTarget = await functions.getStubPointerTarget(functionId, mangledId, pointerTargetName, functions.integratedFuncKey);
    if (pointerTarget) {
      throw new PhoenixError('conflict', `PointerTarget ${pointerTargetName} already exists`);
    }
    await functions.addStubPointerTarget(functionId, mangledId, req.body, functions.integratedFuncKey);
    pointerTarget = await functions.getStubPointerTarget(functionId, mangledId, pointerTargetName, functions.integratedFuncKey);
    res.json(functions.getStubPointerTargetJson(functionId, mangledId, pointerTargetName, pointerTarget));
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function editIntegratedFuncPointerTarget(req, res, next) {
  (async () => {
    const { functionId, mangledId, pointerTargetName } = req.params;
    const {
      pointerTargetName: newPointerTargetName,
      typeName,
      elementTypeName,
      length,
    } = req.body;
    if (!newPointerTargetName) {
      throw new PhoenixError('invalid request', 'Missing parameters. "pointerTargetName" is required');
    }
    if (!typeName && !elementTypeName) {
      throw new PhoenixError('invalid request', 'Missing parameters. "typeName" or "elementTypeName" is required');
    }
    if ((elementTypeName && !length) || (!elementTypeName && length)) {
      throw new PhoenixError('invalid request', 'Missing parameters. "elementTypeName" or "length" is required');
    }
    let pointerTarget;
    if (pointerTargetName !== newPointerTargetName) {
      pointerTarget = await functions.getStubPointerTarget(functionId, mangledId, newPointerTargetName, functions.integratedFuncKey);
      if (pointerTarget) {
        throw new PhoenixError('conflict', `PointerTarget ${newPointerTargetName} already exists`);
      }
    }
    pointerTarget = await functions.getStubPointerTarget(functionId, mangledId, pointerTargetName, functions.integratedFuncKey);
    if (!pointerTarget) {
      throw new PhoenixError('not found', `PointerTarget ${pointerTargetName} not found`);
    }
    await functions.updateStubPointerTarget(functionId, mangledId, pointerTargetName, req.body, pointerTarget, functions.integratedFuncKey);
    pointerTarget = await functions.getStubPointerTarget(functionId, mangledId, newPointerTargetName, functions.integratedFuncKey);
    res.json(functions.getStubPointerTargetJson(functionId, mangledId, newPointerTargetName, pointerTarget));
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function removeIntegratedFuncPointerTarget(req, res, next) {
  (async () => {
    const { functionId, mangledId, pointerTargetName } = req.params;
    await functions.removeStubPointerTarget(
      functionId,
      mangledId,
      pointerTargetName,
      functions.integratedFuncKey
    );
    res.status(204).json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function addIntegratedFuncOutput(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { mangledId } = req.body;
    const content = await functions.addOutputIntegratedFunc(
      functionId,
      mangledId
    );
    await functions.removeResultOfExecution(functionId);
    res.json(content);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function removeIntegratedFuncOutput(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const { mangledId } = req.body;
    await functions.removeOutputIntegratedFunc(
      functionId,
      mangledId
    );
    await functions.removeResultOfExecution(functionId);
    res.status(204).json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getIntegratedFunctions(req, res, next) {
  (async () => {
    if (!req.query.functionType) {
      throw new PhoenixError('invalid request', 'need functionType');
    }
    const resJson = await functions.getIntegratedFunctions(req.params.functionId, req.query.functionType);
    res.json(resJson);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function updateIntegratedFunctions(req, res, next) {
  (async () => {
    if (!req.body.mangledIds) {
      throw new PhoenixError('invalid request', 'need mangledIds');
    }
    await functions.updateIntegratedFunctions(req.params.functionId, req.body.mangledIds);
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function updateSelfDefinedGlobals(req, res, next) {
  (async () => {
    if (!req.body.globals) {
      throw new PhoenixError('invalid request', 'need globals');
    }
    await functions.updateSelfDefinedGlobals(req.params.functionId, req.body.globals);
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function getSelfDefinedGlobals(req, res, next) {
  (async () => {
    const globals = await functions.getSelfDefinedGlobals(req.params.functionId);
    res.json({ globals });
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function setInfiniteLoopTimes(req, res, next) {
  (async () => {
    if (!req.body.infiniteLoop) {
      throw new PhoenixError('invalid request', 'Need field infiniteLoop');
    }
    await functions.setInfiniteLoopTimes(
      Types.ObjectId(req.params.functionId),
      req.body.infiniteLoop
    );
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function getInfiniteLoopTimes(req, res, next) {
  (async () => {
    const list = await functions.getInfiniteLoops(Types.ObjectId(req.params.functionId));
    res.json(list);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function updateFuncBorderVariable(req, res, next) {
  (async () => {
    await functions.updateFuncBorderVariable(req.$function, req.body);
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function getFuncBorderVariable(req, res, next) {
  (async () => {
    const resResult = {
      params: {},
      global: {},
    };
    const result = await functions.getFuncBorderVariable(req.params.functionId);
    if (result) {
      resResult.params = result.params;
      resResult.global = result.global;
    }
    res.json(resResult);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function getCodeInstrmetationCFG(req, res, next) {
  (async () => {
    let cfg = {};
    if (!utility.isEmpty(req.body) && utility.isArrayType(req.body)) {
      cfg = await codeInstrumentations.getFunctionCfg(
        req.params.functionId,
        req.body,
        req.$projectVersion
      );
    }
    res.json(functions.getCFGJson(cfg));
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function integrationSolution(req, res, next) {
  (async () => {
    const result = await functions.integrationSolution(req.params.functionId, req.$projectVersion);
    res.json(result);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function integrationSolutionUpdateFile(req, res, next) {
  (async () => {
    const { functionId } = req.params;
    const {
      type, variableName, fileId, filePath, isExternalGlobal,
    } = req.body;
    if (!type) {
      throw new PhoenixError('invalid request', 'Need "type"');
    }
    if (!variableName) {
      throw new PhoenixError('invalid request', 'Need "variableName"');
    }
    if (!fileId) {
      throw new PhoenixError('invalid request', 'Need "fileId"');
    }
    await functions.integrationSolutionUpdateFile(
      functionId,
      type,
      variableName,
      isExternalGlobal,
      fileId,
      filePath
    );
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function manuallyCover(req, res, next) {
  (async () => {
    const func = req.$function;
    logger.verbose(JSON.stringify(func, null, 1));
    const {
      nodeId, decisionId, condKey, description,
    } = req.body;
    if (description) {
      await functions.manuallyCover(func.versionId, func.fileId, func._id, utility.number2String(nodeId), {
        decisionId: utility.number2String(decisionId), condKey, description,
      });
    } else {
      await functions.manuallyUnCover(func._id, utility.number2String(nodeId), {
        decisionId: utility.number2String(decisionId), condKey,
      });
    }
    res.json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function getFunctionCoverages(req, res, next) {
  (async () => {
    if (!req.body.testcaseIds) {
      throw new PhoenixError('invalid request', 'Need "testcaseIds"');
    }
    const result = await functions.getFunctionCoverages(
      req.params.functionId,
      req.body.testcaseIds,
      req.$projectVersion
    );
    res.json(result);
  })().catch((err) => next(new PhoenixError(err)));
}

function getIntegrationCoveredDetail(req, res, next) {
  (async () => {
    const result = await functions.getIntegrationCoveredDetail(req.params.functionId, req.$projectVersion._id);
    res.json(result);
  })().catch((err) => next(new PhoenixError(err)));
}
/**
 * Export model definition object.
 */
module.exports = (app, prefix) => {
  const functionsURL = `${prefix}/files/:fileId/functions.json`;
  const allFunctionsURL = `${prefix}/project-versions/:projectVersionId/functions.json`;
  const functionURL = `${prefix}/functions/:functionId.json`;
  const cfgURL = `${prefix}/functions/:functionId/cfg.json`;
  const codeInstrumentationsCfgURL = `${prefix}/project-versions/:projectVersionId/code-instrumentations/functions/:functionId/cfg.json`;
  const variablesURL = `${prefix}/functions/:functionId/variables.json`;
  const globalOutputURL = `${prefix}/functions/:functionId/variables/output/global.json`;
  const fixedAddressOutputURL = `${prefix}/functions/:functionId/variables/output/fixedAddress.json`;
  const fixedAddressOutputVariableURL = `${prefix}/functions/:functionId/variables/output/fixedAddress/:variableName.json`;
  const staticsOutputURL = `${prefix}/functions/:functionId/variables/output/statics.json`;
  const staticsOutputVariableURL = `${prefix}/functions/:functionId/variables/output/statics/:index.json`;
  const globalOutputVariableURL = `${prefix}/functions/:functionId/variables/output/global/:variableName.json`;
  const mallocOutputURL = `${prefix}/functions/:functionId/variables/output/malloc.json`;
  const mallocOutputVariableURL = `${prefix}/functions/:functionId/variables/output/malloc/:variableName.json`;
  const objectOutputURL = `${prefix}/functions/:functionId/variables/output/object.json`;
  const mallocURL = `${prefix}/functions/:functionId/malloc.json`;
  const mallocVariableURL = `${prefix}/functions/:functionId/malloc/:variableName.json`;
  const stubPointerTargetsURL = `${prefix}/functions/:functionId/stubs/:stubName/pointer-targets.json`;
  const stubPointerTargetURL = `${prefix}/functions/:functionId/stubs/:stubName/pointer-targets/:pointerTargetName.json`;
  const fixedAddressesURL = `${prefix}/functions/:functionId/fixed-addresses.json`;
  const fixedAddressURL = `${prefix}/functions/:functionId/fixed-addresses/:fixedAddressName.json`;
  const fixedAddressExprURL = `${prefix}/functions/:functionId/fixed-address-exprs/:exprName.json`;
  const fixedAddressExprsURL = `${prefix}/functions/:functionId/fixed-address-exprs.json`;
  const stubsURL = `${prefix}/functions/:functionId/stubs.json`;
  const stubURL = `${prefix}/functions/:functionId/stubs/:stubName.json`;
  const integrationStubsURL = `${prefix}/functions/:functionId/integration-functions/stubs.json`;
  const integrationInvokeFilesURL = `${prefix}/functions/:functionId/integration-functions/:mangledId/invoke-files.json`;
  const funcInvokesURL = `${prefix}/functions/:functionId/invokes.json`;
  const funcInvokeFilesURL = `${prefix}/:projectVersionId/functions/:mangledId/invoke-files.json`;

  const allFunctionsOverviewUrl = `${prefix}/project-versions/:projectVersionId/functions/overview.json`;
  const downloadFunctionsOverviewUrl = `${prefix}/project-versions/:projectVersionId/functions/overview.xlsx`;
  const getGlobalListUrl = `${prefix}/functions/:functionId/external-globals.json`;
  const invokeGraphUrl = `${prefix}/functions/:functionId/invoke-graph.json`;
  const invokeChildrenUrl = `${prefix}/functions/:functionId/invoke-children.json`;
  const callExprTimesUrl = `${prefix}/functions/:functionId/call-count.json`;
  const integrationRelationStubsURL = `${prefix}/functions/:functionId/integration-functions/batch-stubs.json`;
  const integrationFixedAddressExprsURL = `${prefix}/functions/:functionId/integration-functions/fixed-addrs-exprs.json`;
  const integrationFixedAddressURL = `${prefix}/functions/:functionId/integration-functions/fixed-addrs.json`;
  const invokeCoveredLocationsURL = `${prefix}/functions/:functionId/invoke-covered-locations.json`;
  const integratedFuncsPointerTargetsURL = `${prefix}/functions/:functionId/integrated-functions/:mangledId/pointer-targets.json`;
  const integratedFuncsPointerTargetURL = `${prefix}/functions/:functionId/integrated-functions/:mangledId/pointer-targets/:pointerTargetName.json`;
  const integratedFuncsOutputURL = `${prefix}/functions/:functionId/output/integrated-functions-params.json`;
  const integratedFunctionsUrl = `${prefix}/functions/:functionId/integrated-functions.json`;
  const selfDefinedGlobalsUrl = `${prefix}/functions/:functionId/self-defined-globals.json`;
  const getSelfDefinedGlobalsUrl = `${prefix}/functions/self-defined-globals/:functionId.json`;
  const integrattionSolutionURL = `${prefix}/functions/:functionId/integration-solution.json`;
  const integrattionSolutionUpdateFileURL = `${prefix}/functions/integration/solution/:functionId/variable-file.json`;

  const infiniteLoopsUrl = `${prefix}/functions/:functionId/infinite-loop.json`;

  const funcBorderVariableUrl = `${prefix}/functions/border-variables/:functionId.json`;

  const manuallyCoverUrl = `${prefix}/functions/:functionId/manually-cover.json`;
  const testcaseCoverageUrl = `${prefix}/functions/:functionId/coverages.json`;
  const integrationCoveredDetail = `${prefix}/functions/:functionId/integration-covered-detail.json`;

  // 获取当前函数的函数调用函数
  app.get(funcInvokesURL, middleware.user.requireTokenUnexpired);
  app.get(funcInvokesURL, middleware.user.requireAvailable);
  app.get(funcInvokesURL, middleware.user.requireTester);
  app.get(funcInvokesURL, middleware.function.requireFunctionExist);
  app.get(funcInvokesURL, middleware.project.requireProjectAccess);
  app.get(funcInvokesURL, getFuncInvokes);

  // 获取当前函数可选文件 (deprecated)
  app.get(funcInvokeFilesURL, middleware.user.requireTokenUnexpired);
  app.get(funcInvokeFilesURL, middleware.user.requireAvailable);
  app.get(funcInvokeFilesURL, middleware.user.requireTester);
  app.get(funcInvokeFilesURL, middleware.projectVersion.requireProjectVersionExist);
  app.get(funcInvokeFilesURL, getFuncInvokeFiles);

  // 获取函数信息
  app.get(functionURL, middleware.user.requireTokenUnexpired);
  app.get(functionURL, middleware.user.requireAvailable);
  app.get(functionURL, middleware.user.requireTester);
  app.get(functionURL, middleware.function.requireFunctionExist);
  app.get(functionURL, middleware.project.requireProjectAccess);
  app.get(functionURL, getFunction);

  // 编辑函数信息
  app.put(functionURL, middleware.user.requireTokenUnexpired);
  app.put(functionURL, middleware.user.requireAvailable);
  app.put(functionURL, middleware.user.requireTester);
  app.put(functionURL, middleware.function.requireFunctionExist);
  app.put(functionURL, middleware.user.getLockByVersion());
  app.put(functionURL, middleware.project.requireProjectAccess);
  app.put(functionURL, middleware.function.parseFunctionQuery);
  app.put(functionURL, updateFunction);

  // 批量编辑函数信息
  app.put(allFunctionsURL, middleware.user.requireTokenUnexpired);
  app.put(allFunctionsURL, middleware.user.requireAvailable);
  app.put(allFunctionsURL, middleware.user.requireTester);
  app.put(allFunctionsURL, middleware.projectVersion.requireProjectVersionExist);
  app.put(allFunctionsURL, middleware.user.getLockByVersion());
  app.put(allFunctionsURL, middleware.project.requireProjectAccess);
  app.put(allFunctionsURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(allFunctionsURL, middleware.project.requireProjectAvailable);
  app.put(allFunctionsURL, middleware.file.parseFileListQuery);
  app.put(allFunctionsURL, middleware.function.parseFunctionListQuery);
  app.put(allFunctionsURL, middleware.file.getFiles);
  app.put(allFunctionsURL, middleware.function.parseFunctionQuery);
  app.put(allFunctionsURL, updateFunctions);

  // 获取函数列表
  app.get(functionsURL, middleware.user.requireTokenUnexpired);
  app.get(functionsURL, middleware.user.requireAvailable);
  app.get(functionsURL, middleware.user.requireTester);
  app.get(functionsURL, middleware.file.requireFileExist);
  app.get(functionsURL, middleware.project.requireProjectAccess);
  app.get(functionsURL, middleware.splitFilter);
  app.get(functionsURL, getFunctions);

  // 获取函数CFG数据
  app.get(cfgURL, middleware.user.requireTokenUnexpired);
  app.get(cfgURL, middleware.user.requireAvailable);
  app.get(cfgURL, middleware.user.requireTester);
  app.get(cfgURL, middleware.function.requireFunctionCFGExist);
  app.get(cfgURL, middleware.project.requireProjectAccess);
  app.get(cfgURL, getFunctionCFG);

  // 获取插桩函数CFG数据
  app.post(codeInstrumentationsCfgURL, middleware.user.requireTokenUnexpired);
  app.post(codeInstrumentationsCfgURL, middleware.user.requireAvailable);
  app.post(codeInstrumentationsCfgURL, middleware.user.requireTester);
  app.post(codeInstrumentationsCfgURL, middleware.function.requireFunctionExist);
  app.post(codeInstrumentationsCfgURL, middleware.project.requireProjectAccess);
  app.post(codeInstrumentationsCfgURL, getCodeInstrmetationCFG);

  // 获取函数变量信息
  app.get(variablesURL, middleware.user.requireTokenUnexpired);
  app.get(variablesURL, middleware.user.requireAvailable);
  app.get(variablesURL, middleware.user.requireTester);
  app.get(variablesURL, middleware.function.requireFunctionVariablesExist);
  app.get(variablesURL, middleware.project.requireProjectAccess);
  app.get(variablesURL, getFunctionVariables);

  // 设置全局变量检查项
  app.post(globalOutputURL, middleware.user.requireTokenUnexpired);
  app.post(globalOutputURL, middleware.user.requireAvailable);
  app.post(globalOutputURL, middleware.user.requireTester);
  app.post(globalOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(globalOutputURL, middleware.user.getLockByVersion());
  app.post(globalOutputURL, middleware.project.requireProjectAccess);
  app.post(globalOutputURL, middleware.project.requireProjectAvailable);
  app.post(globalOutputURL, middleware.file.requireFileAvailable);
  app.post(globalOutputURL, addGlobalOutput);

  // 取消全局变量检查项
  app.delete(globalOutputVariableURL, middleware.user.requireTokenUnexpired);
  app.delete(globalOutputVariableURL, middleware.user.requireAvailable);
  app.delete(globalOutputVariableURL, middleware.user.requireTester);
  app.delete(globalOutputVariableURL, middleware.function.requireFunctionVariablesExist);
  app.delete(globalOutputVariableURL, middleware.user.getLockByVersion());
  app.delete(globalOutputVariableURL, middleware.project.requireProjectAvailable);
  app.delete(globalOutputVariableURL, middleware.project.requireProjectAccess);
  app.delete(globalOutputVariableURL, middleware.file.requireFileAvailable);
  app.delete(globalOutputVariableURL, removeGlobalOutputVariable);

  // 设置指针目标检查项
  app.post(mallocOutputURL, middleware.user.requireTokenUnexpired);
  app.post(mallocOutputURL, middleware.user.requireAvailable);
  app.post(mallocOutputURL, middleware.user.requireTester);
  app.post(mallocOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(mallocOutputURL, middleware.user.getLockByVersion());
  app.post(mallocOutputURL, middleware.project.requireProjectAccess);
  app.post(mallocOutputURL, middleware.project.requireProjectAvailable);
  app.post(mallocOutputURL, middleware.file.requireFileAvailable);
  app.post(mallocOutputURL, addMallocOutput);

  // 取消指针目标检查项
  app.delete(mallocOutputVariableURL, middleware.user.requireTokenUnexpired);
  app.delete(mallocOutputVariableURL, middleware.user.requireAvailable);
  app.delete(mallocOutputVariableURL, middleware.user.requireTester);
  app.delete(mallocOutputVariableURL, middleware.function.requireFunctionVariablesExist);
  app.delete(mallocOutputVariableURL, middleware.user.getLockByVersion());
  app.delete(mallocOutputVariableURL, middleware.project.requireProjectAccess);
  app.delete(mallocOutputVariableURL, middleware.project.requireProjectAvailable);
  app.delete(mallocOutputVariableURL, middleware.file.requireFileAvailable);
  app.delete(mallocOutputVariableURL, removeMallocOutputVariable);

  // 设置成员函数所属类检查项
  app.post(objectOutputURL, middleware.user.requireTokenUnexpired);
  app.post(objectOutputURL, middleware.user.requireAvailable);
  app.post(objectOutputURL, middleware.user.requireTester);
  app.post(objectOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(objectOutputURL, middleware.user.getLockByVersion());
  app.post(objectOutputURL, middleware.project.requireProjectAccess);
  app.post(objectOutputURL, middleware.project.requireProjectAvailable);
  app.post(objectOutputURL, middleware.file.requireFileAvailable);
  app.post(objectOutputURL, addObjectOutput);

  // 取消成员函数所属类检查项
  app.delete(objectOutputURL, middleware.user.requireTokenUnexpired);
  app.delete(objectOutputURL, middleware.user.requireAvailable);
  app.delete(objectOutputURL, middleware.user.requireTester);
  app.delete(objectOutputURL, middleware.function.requireFunctionVariablesExist);
  app.delete(objectOutputURL, middleware.user.getLockByVersion());
  app.delete(objectOutputURL, middleware.project.requireProjectAccess);
  app.delete(objectOutputURL, middleware.project.requireProjectAvailable);
  app.delete(objectOutputURL, middleware.file.requireFileAvailable);
  app.delete(objectOutputURL, removeObjectOutputVariable);

  // 设置绝对地址检查项
  app.post(fixedAddressOutputURL, middleware.user.requireTokenUnexpired);
  app.post(fixedAddressOutputURL, middleware.user.requireAvailable);
  app.post(fixedAddressOutputURL, middleware.user.requireTester);
  app.post(fixedAddressOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(fixedAddressOutputURL, middleware.user.getLockByVersion());
  app.post(fixedAddressOutputURL, middleware.project.requireProjectAccess);
  app.post(fixedAddressOutputURL, middleware.project.requireProjectAvailable);
  app.post(fixedAddressOutputURL, middleware.file.requireFileAvailable);
  app.post(fixedAddressOutputURL, addFixedAddressOutput);

  // 取消绝对地址检查项
  app.delete(fixedAddressOutputVariableURL, middleware.user.requireTokenUnexpired);
  app.delete(fixedAddressOutputVariableURL, middleware.user.requireAvailable);
  app.delete(fixedAddressOutputVariableURL, middleware.user.requireTester);
  app.delete(fixedAddressOutputVariableURL, middleware.function.requireFunctionVariablesExist);
  app.delete(fixedAddressOutputVariableURL, middleware.user.getLockByVersion());
  app.delete(fixedAddressOutputVariableURL, middleware.project.requireProjectAccess);
  app.delete(fixedAddressOutputVariableURL, middleware.project.requireProjectAvailable);
  app.delete(fixedAddressOutputVariableURL, middleware.file.requireFileAvailable);
  app.delete(fixedAddressOutputVariableURL, removeFixedAddressOutput);

  // 设置静态变量检查项
  app.post(staticsOutputURL, middleware.user.requireTokenUnexpired);
  app.post(staticsOutputURL, middleware.user.requireAvailable);
  app.post(staticsOutputURL, middleware.user.requireTester);
  app.post(staticsOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(staticsOutputURL, middleware.user.getLockByVersion());
  app.post(staticsOutputURL, middleware.project.requireProjectAccess);
  app.post(staticsOutputURL, middleware.project.requireProjectAvailable);
  app.post(staticsOutputURL, middleware.file.requireFileAvailable);
  app.post(staticsOutputURL, addStaticsOutputVariable);

  // 取消静态变量检查项
  app.delete(staticsOutputVariableURL, middleware.user.requireTokenUnexpired);
  app.delete(staticsOutputVariableURL, middleware.user.requireAvailable);
  app.delete(staticsOutputVariableURL, middleware.user.requireTester);
  app.delete(staticsOutputVariableURL, middleware.function.requireFunctionVariablesExist);
  app.delete(staticsOutputVariableURL, middleware.user.getLockByVersion());
  app.delete(staticsOutputVariableURL, middleware.project.requireProjectAccess);
  app.delete(staticsOutputVariableURL, middleware.project.requireProjectAvailable);
  app.delete(staticsOutputVariableURL, middleware.file.requireFileAvailable);
  app.delete(staticsOutputVariableURL, removeStaticsOutputVariable);

  // 添加指针目标
  app.post(mallocURL, middleware.user.requireTokenUnexpired);
  app.post(mallocURL, middleware.user.requireAvailable);
  app.post(mallocURL, middleware.user.requireTester);
  app.post(mallocURL, middleware.function.requireFunctionVariablesExist);
  app.post(mallocURL, middleware.user.getLockByVersion());
  app.post(mallocURL, middleware.function.requireLegalIdentifier);
  app.post(mallocURL, middleware.function.checkIdentifierConflict);
  app.post(mallocURL, middleware.project.requireProjectAccess);
  app.post(mallocURL, middleware.project.requireProjectAvailable);
  app.post(mallocURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(mallocURL, middleware.file.requireFileAvailable);
  app.post(mallocURL, addMallocVariable);

  // 获取指针目标信息
  app.get(mallocVariableURL, middleware.user.requireTokenUnexpired);
  app.get(mallocVariableURL, middleware.user.requireAvailable);
  app.get(mallocVariableURL, middleware.user.requireTester);
  app.get(mallocVariableURL, middleware.function.requireFunctionVariablesExist);
  app.get(mallocVariableURL, middleware.function.requireMallocVariableExist);
  app.get(mallocVariableURL, middleware.project.requireProjectAccess);
  app.get(mallocVariableURL, getMallocVariable);

  // 删除指针目标
  app.delete(mallocVariableURL, middleware.user.requireTokenUnexpired);
  app.delete(mallocVariableURL, middleware.user.requireAvailable);
  app.delete(mallocVariableURL, middleware.user.requireTester);
  app.delete(mallocVariableURL, middleware.function.requireFunctionVariablesExist);
  app.delete(mallocVariableURL, middleware.user.getLockByVersion());
  app.delete(mallocVariableURL, middleware.function.requireMallocVariableExist);
  app.delete(mallocVariableURL, middleware.project.requireProjectAccess);
  app.delete(mallocVariableURL, middleware.project.requireProjectAvailable);
  app.delete(mallocVariableURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.delete(mallocVariableURL, middleware.file.requireFileAvailable);
  app.delete(mallocVariableURL, removeMallocVariable);

  // 编辑指针目标
  app.put(mallocVariableURL, middleware.user.requireTokenUnexpired);
  app.put(mallocVariableURL, middleware.user.requireAvailable);
  app.put(mallocVariableURL, middleware.user.requireTester);
  app.put(mallocVariableURL, middleware.function.requireFunctionVariablesExist);
  app.put(mallocVariableURL, middleware.user.getLockByVersion());
  app.put(mallocVariableURL, middleware.function.requireMallocVariableExist);
  app.put(mallocVariableURL, middleware.function.requireLegalIdentifier);
  app.put(mallocVariableURL, middleware.function.checkIdentifierConflict);
  app.put(mallocVariableURL, middleware.project.requireProjectAccess);
  app.put(mallocVariableURL, middleware.project.requireProjectAvailable);
  app.put(mallocVariableURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(mallocVariableURL, middleware.file.requireFileAvailable);
  app.put(mallocVariableURL, updateMallocVariable);

  // 添加桩函数
  app.post(stubsURL, middleware.user.requireTokenUnexpired);
  app.post(stubsURL, middleware.user.requireAvailable);
  app.post(stubsURL, middleware.user.requireTester);
  app.post(stubsURL, middleware.function.requireFunctionVariablesExist);
  app.post(stubsURL, middleware.user.getLockByVersion());
  app.post(stubsURL, middleware.function.requireParamNamesValid);
  app.post(stubsURL, middleware.function.requireLegalIdentifier);
  app.post(stubsURL, middleware.function.checkIdentifierConflict);
  app.post(stubsURL, middleware.project.requireProjectAccess);
  app.post(stubsURL, middleware.project.requireProjectAvailable);
  app.post(stubsURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(stubsURL, middleware.file.requireFileAvailable);
  app.post(stubsURL, addStub);

  // 获取桩函数
  app.get(stubURL, middleware.user.requireTokenUnexpired);
  app.get(stubURL, middleware.user.requireAvailable);
  app.get(stubURL, middleware.user.requireTester);
  app.get(stubURL, middleware.function.requireFunctionVariablesExist);
  app.get(stubURL, middleware.function.requireStubExist);
  app.get(stubURL, middleware.project.requireProjectAccess);
  app.get(stubURL, middleware.project.requireProjectAvailable);
  app.get(stubURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.get(stubURL, getStub);

  // 删除桩函数
  app.delete(stubURL, middleware.user.requireTokenUnexpired);
  app.delete(stubURL, middleware.user.requireAvailable);
  app.delete(stubURL, middleware.user.requireTester);
  app.delete(stubURL, middleware.function.requireFunctionVariablesExist);
  app.delete(stubURL, middleware.user.getLockByVersion());
  app.delete(stubURL, middleware.function.requireStubExist);
  app.delete(stubURL, middleware.function.requireStubModifiable);
  app.delete(stubURL, middleware.project.requireProjectAccess);
  app.delete(stubURL, middleware.project.requireProjectAvailable);
  app.delete(stubURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.delete(stubURL, middleware.file.requireFileAvailable);
  app.delete(stubURL, removeStub);

  // 编辑桩函数
  app.put(stubURL, middleware.user.requireTokenUnexpired);
  app.put(stubURL, middleware.user.requireAvailable);
  app.put(stubURL, middleware.user.requireTester);
  app.put(stubURL, middleware.function.requireFunctionVariablesExist);
  app.put(stubURL, middleware.user.getLockByVersion());
  app.put(stubURL, middleware.function.requireStubExist);
  app.put(stubURL, middleware.function.requireStubModifiable);
  app.put(stubURL, middleware.function.requireParamNamesValid);
  app.put(stubURL, middleware.function.requireLegalIdentifier);
  app.put(stubURL, middleware.function.checkIdentifierConflict);
  app.put(stubURL, middleware.project.requireProjectAccess);
  app.put(stubURL, middleware.project.requireProjectAvailable);
  app.put(stubURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(stubURL, middleware.file.requireFileAvailable);
  app.put(stubURL, updateStub);

  // 添加桩函数指针目标
  app.post(stubPointerTargetsURL, middleware.user.requireTokenUnexpired);
  app.post(stubPointerTargetsURL, middleware.user.requireAvailable);
  app.post(stubPointerTargetsURL, middleware.user.requireTester);
  app.post(stubPointerTargetsURL, middleware.function.requireFunctionVariablesExist);
  app.post(stubPointerTargetsURL, middleware.user.getLockByVersion());
  app.post(stubPointerTargetsURL, middleware.project.requireProjectAccess);
  app.post(stubPointerTargetsURL, middleware.project.requireProjectAvailable);
  app.post(stubPointerTargetsURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(stubPointerTargetsURL, middleware.file.requireFileAvailable);
  app.post(stubPointerTargetsURL, addStubPointerTarget);

  // 获取桩函数指针目标信息
  app.get(stubPointerTargetURL, middleware.user.requireTokenUnexpired);
  app.get(stubPointerTargetURL, middleware.user.requireAvailable);
  app.get(stubPointerTargetURL, middleware.user.requireTester);
  app.get(stubPointerTargetURL, middleware.function.requireFunctionVariablesExist);
  app.get(stubPointerTargetURL, middleware.function.requireStubPointerTargetExist);
  app.get(stubPointerTargetURL, middleware.project.requireProjectAccess);
  app.get(stubPointerTargetURL, getStubPointerTarget);

  // 删除桩函数指针目标
  app.delete(stubPointerTargetURL, middleware.user.requireTokenUnexpired);
  app.delete(stubPointerTargetURL, middleware.user.requireAvailable);
  app.delete(stubPointerTargetURL, middleware.user.requireTester);
  app.delete(stubPointerTargetURL, middleware.function.requireFunctionVariablesExist);
  app.delete(stubPointerTargetURL, middleware.user.getLockByVersion());
  app.delete(stubPointerTargetURL, middleware.function.requireStubPointerTargetExist);
  app.delete(stubPointerTargetURL, middleware.project.requireProjectAccess);
  app.delete(stubPointerTargetURL, middleware.project.requireProjectAvailable);
  app.delete(stubPointerTargetURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.delete(stubPointerTargetURL, middleware.file.requireFileAvailable);
  app.delete(stubPointerTargetURL, removeStubPointerTarget);

  // 编辑桩函数指针目标
  app.put(stubPointerTargetURL, middleware.user.requireTokenUnexpired);
  app.put(stubPointerTargetURL, middleware.user.requireAvailable);
  app.put(stubPointerTargetURL, middleware.user.requireTester);
  app.put(stubPointerTargetURL, middleware.function.requireFunctionVariablesExist);
  app.put(stubPointerTargetURL, middleware.user.getLockByVersion());
  app.put(stubPointerTargetURL, middleware.function.requireStubPointerTargetExist);
  app.put(stubPointerTargetURL, middleware.project.requireProjectAccess);
  app.put(stubPointerTargetURL, middleware.project.requireProjectAvailable);
  app.put(stubPointerTargetURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(stubPointerTargetURL, middleware.file.requireFileAvailable);
  app.put(stubPointerTargetURL, updateStubPointerTarget);

  // 添加绝对地址
  app.post(fixedAddressesURL, middleware.user.requireTokenUnexpired);
  app.post(fixedAddressesURL, middleware.user.requireAvailable);
  app.post(fixedAddressesURL, middleware.user.requireTester);
  app.post(fixedAddressesURL, middleware.function.requireFunctionVariablesExist);
  app.post(fixedAddressesURL, middleware.user.getLockByVersion());
  app.post(fixedAddressesURL, middleware.function.requireLegalFixedAddressName);
  app.post(fixedAddressesURL, middleware.project.requireProjectAccess);
  app.post(fixedAddressesURL, middleware.project.requireProjectAvailable);
  app.post(fixedAddressesURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(fixedAddressesURL, middleware.file.requireFileAvailable);
  app.post(fixedAddressesURL, middleware.function.requireRefactorPointerTargetType);
  app.post(fixedAddressesURL, addFixedAddress);

  // 编辑绝对地址
  app.put(fixedAddressURL, middleware.user.requireTokenUnexpired);
  app.put(fixedAddressURL, middleware.user.requireAvailable);
  app.put(fixedAddressURL, middleware.user.requireTester);
  app.put(fixedAddressURL, middleware.function.requireFunctionVariablesExist);
  app.put(fixedAddressURL, middleware.user.getLockByVersion());
  app.put(fixedAddressURL, middleware.function.requireFixedAddressExist);
  app.put(fixedAddressURL, middleware.function.requireLegalFixedAddressName);
  app.put(fixedAddressURL, middleware.project.requireProjectAccess);
  app.put(fixedAddressURL, middleware.project.requireProjectAvailable);
  app.put(fixedAddressURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(fixedAddressURL, middleware.file.requireFileAvailable);
  app.put(fixedAddressURL, middleware.function.requireRefactorPointerTargetType);
  app.put(fixedAddressURL, updateFixedAddress);

  // 删除绝对地址
  app.delete(fixedAddressURL, middleware.user.requireTokenUnexpired);
  app.delete(fixedAddressURL, middleware.user.requireAvailable);
  app.delete(fixedAddressURL, middleware.user.requireTester);
  app.delete(fixedAddressURL, middleware.function.requireFunctionVariablesExist);
  app.delete(fixedAddressURL, middleware.user.getLockByVersion());
  app.delete(fixedAddressURL, middleware.project.requireProjectAccess);
  app.delete(fixedAddressURL, middleware.project.requireProjectAvailable);
  app.delete(fixedAddressURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.delete(fixedAddressURL, middleware.file.requireFileAvailable);
  app.delete(fixedAddressURL, removeFixedAddress);

  // 获取绝对地址
  app.get(fixedAddressURL, middleware.user.requireTokenUnexpired);
  app.get(fixedAddressURL, middleware.user.requireAvailable);
  app.get(fixedAddressURL, middleware.user.requireTester);
  app.get(fixedAddressURL, middleware.function.requireFunctionVariablesExist);
  app.get(fixedAddressURL, middleware.function.requireFixedAddressExist);
  app.get(fixedAddressURL, middleware.project.requireProjectAccess);
  app.get(fixedAddressURL, getFixedAddress);

  // 获取可手动添加绝对地址表达式列表
  app.get(fixedAddressExprsURL, middleware.user.requireTokenUnexpired);
  app.get(fixedAddressExprsURL, middleware.user.requireAvailable);
  app.get(fixedAddressExprsURL, middleware.user.requireTester);
  app.get(fixedAddressExprsURL, middleware.function.requireFunctionVariablesExist);
  app.get(fixedAddressExprsURL, middleware.project.requireProjectAccess);
  app.get(fixedAddressExprsURL, getFixedAddressExprs);

  // 手动添加绝对地址
  app.post(fixedAddressExprsURL, middleware.user.requireTokenUnexpired);
  app.post(fixedAddressExprsURL, middleware.user.requireAvailable);
  app.post(fixedAddressExprsURL, middleware.user.requireTester);
  app.post(fixedAddressExprsURL, middleware.function.requireFunctionVariablesExist);
  app.post(fixedAddressExprsURL, middleware.user.getLockByVersion());
  app.post(fixedAddressExprsURL, middleware.project.requireProjectAccess);
  app.post(fixedAddressExprsURL, addFixedAddressExprs);

  // 删除手动添加的绝对地址
  app.delete(fixedAddressExprURL, middleware.user.requireTokenUnexpired);
  app.delete(fixedAddressExprURL, middleware.user.requireAvailable);
  app.delete(fixedAddressExprURL, middleware.user.requireTester);
  app.delete(fixedAddressExprURL, middleware.function.requireFunctionVariablesExist);
  app.delete(fixedAddressExprURL, middleware.user.getLockByVersion());
  app.delete(fixedAddressExprURL, middleware.function.requireFixedAddressExprExist);
  app.delete(fixedAddressExprURL, middleware.project.requireProjectAccess);
  app.delete(fixedAddressExprURL, removeFixedAddressExpr);

  // 项目信息总览-函数列表
  app.get(allFunctionsOverviewUrl, middleware.user.requireTokenUnexpired);
  app.get(allFunctionsOverviewUrl, middleware.user.requireAvailable);
  app.get(allFunctionsOverviewUrl, middleware.user.requireTester);
  app.get(allFunctionsOverviewUrl, middleware.projectVersion.requireProjectVersionExist);
  app.get(allFunctionsOverviewUrl, middleware.project.requireProjectAccess);
  app.get(allFunctionsOverviewUrl, allFunctionsOverview);

  // 项目信息总览-函数列表下载
  app.get(downloadFunctionsOverviewUrl, middleware.user.requireTokenUnexpired);
  app.get(downloadFunctionsOverviewUrl, middleware.user.requireAvailable);
  app.get(downloadFunctionsOverviewUrl, middleware.user.requireTester);
  app.get(downloadFunctionsOverviewUrl, middleware.projectVersion.requireProjectVersionExist);
  app.get(downloadFunctionsOverviewUrl, middleware.project.requireProjectAccess);
  app.get(downloadFunctionsOverviewUrl, exportFunctionsOverview);

  app.put(integrationStubsURL, middleware.user.requireTokenUnexpired);
  app.put(integrationStubsURL, middleware.user.requireAvailable);
  app.put(integrationStubsURL, middleware.user.requireTester);
  app.put(integrationStubsURL, middleware.function.requireFunctionExist);
  app.put(integrationStubsURL, middleware.user.getLockByVersion());
  app.put(integrationStubsURL, middleware.project.requireProjectAccess);
  app.put(integrationStubsURL, middleware.project.requireProjectAvailable);
  app.put(integrationStubsURL, updateStubStatus);

  app.put(integrationInvokeFilesURL, middleware.user.requireTokenUnexpired);
  app.put(integrationInvokeFilesURL, middleware.user.requireAvailable);
  app.put(integrationInvokeFilesURL, middleware.user.requireTester);
  app.put(integrationInvokeFilesURL, middleware.function.requireFunctionExist);
  app.put(integrationInvokeFilesURL, middleware.user.getLockByVersion());
  app.put(integrationInvokeFilesURL, middleware.project.requireProjectAccess);
  app.put(integrationInvokeFilesURL, middleware.project.requireProjectAvailable);
  app.put(integrationInvokeFilesURL, updateInvokeFile);

  // 获取外部变量可选list
  app.get(getGlobalListUrl, middleware.user.requireTokenUnexpired);
  app.get(getGlobalListUrl, middleware.user.requireAvailable);
  app.get(getGlobalListUrl, middleware.user.requireTester);
  app.get(getGlobalListUrl, middleware.function.requireFunctionExist);
  app.get(getGlobalListUrl, middleware.project.requireProjectAccess);
  app.get(getGlobalListUrl, getExternalGlobals);

  // 添加外部变量
  app.put(getGlobalListUrl, middleware.user.requireTokenUnexpired);
  app.put(getGlobalListUrl, middleware.user.requireAvailable);
  app.put(getGlobalListUrl, middleware.user.requireTester);
  app.put(getGlobalListUrl, middleware.function.requireFunctionExist);
  app.put(getGlobalListUrl, middleware.user.getLockByVersion());
  app.put(getGlobalListUrl, middleware.project.requireProjectAccess);
  app.put(getGlobalListUrl, addExternalGlobals);

  // 获取调用关系图 (deprecated)
  app.get(invokeGraphUrl, middleware.user.requireTokenUnexpired);
  app.get(invokeGraphUrl, middleware.user.requireAvailable);
  app.get(invokeGraphUrl, middleware.user.requireTester);
  app.get(invokeGraphUrl, middleware.function.requireFunctionExist);
  app.get(invokeGraphUrl, middleware.project.requireProjectAccess);
  app.get(invokeGraphUrl, invokeGraph);

  // 获取调函数调用关系下一层函数
  app.get(invokeChildrenUrl, middleware.user.requireTokenUnexpired);
  app.get(invokeChildrenUrl, middleware.user.requireAvailable);
  app.get(invokeChildrenUrl, middleware.user.requireTester);
  app.get(invokeChildrenUrl, middleware.function.requireFunctionExist);
  app.get(invokeChildrenUrl, middleware.project.requireProjectAccess);
  app.get(invokeChildrenUrl, getInvokeChildren);

  app.post(callExprTimesUrl, middleware.user.requireTokenUnexpired);
  app.post(callExprTimesUrl, middleware.user.requireAvailable);
  app.post(callExprTimesUrl, middleware.user.requireTester);
  app.post(callExprTimesUrl, middleware.function.requireFunctionExist);
  app.post(callExprTimesUrl, middleware.project.requireProjectAccess);
  app.post(callExprTimesUrl, getTestCallExprs);

  app.put(integrationRelationStubsURL, middleware.user.requireTokenUnexpired);
  app.put(integrationRelationStubsURL, middleware.user.requireAvailable);
  app.put(integrationRelationStubsURL, middleware.user.requireTester);
  app.put(integrationRelationStubsURL, middleware.function.requireFunctionExist);
  app.put(integrationRelationStubsURL, middleware.user.getLockByVersion());
  app.put(integrationRelationStubsURL, middleware.project.requireProjectAccess);
  app.put(integrationRelationStubsURL, middleware.project.requireProjectAvailable);
  app.put(integrationRelationStubsURL, updateAllRelationStubStatusByFunctionId);

  app.get(integrationFixedAddressURL, middleware.user.requireTokenUnexpired);
  app.get(integrationFixedAddressURL, middleware.user.requireAvailable);
  app.get(integrationFixedAddressURL, middleware.user.requireTester);
  app.get(integrationFixedAddressURL, middleware.function.requireFunctionExist);
  app.get(integrationFixedAddressURL, middleware.project.requireProjectAccess);
  app.get(integrationFixedAddressURL, middleware.project.requireProjectAvailable);
  app.get(integrationFixedAddressURL, getIntegrationFixedAddress);

  app.get(integrationFixedAddressExprsURL, middleware.user.requireTokenUnexpired);
  app.get(integrationFixedAddressExprsURL, middleware.user.requireAvailable);
  app.get(integrationFixedAddressExprsURL, middleware.user.requireTester);
  app.get(integrationFixedAddressExprsURL, middleware.function.requireFunctionExist);
  app.get(integrationFixedAddressExprsURL, middleware.project.requireProjectAccess);
  app.get(integrationFixedAddressExprsURL, middleware.project.requireProjectAvailable);
  app.get(integrationFixedAddressExprsURL, getIntegrationFixedAddressExprs);

  app.post(integrationFixedAddressExprsURL, middleware.user.requireTokenUnexpired);
  app.post(integrationFixedAddressExprsURL, middleware.user.requireAvailable);
  app.post(integrationFixedAddressExprsURL, middleware.user.requireTester);
  app.post(integrationFixedAddressExprsURL, middleware.function.requireFunctionExist);
  app.post(integrationFixedAddressExprsURL, middleware.project.requireProjectAccess);
  app.post(integrationFixedAddressExprsURL, middleware.project.requireProjectAvailable);
  app.post(integrationFixedAddressExprsURL, saveIntegrationFixedAddressExprs);

  app.post(invokeCoveredLocationsURL, middleware.user.requireTokenUnexpired);
  app.post(invokeCoveredLocationsURL, middleware.user.requireAvailable);
  app.post(invokeCoveredLocationsURL, middleware.user.requireTester);
  app.post(invokeCoveredLocationsURL, middleware.function.requireFunctionExist);
  app.post(invokeCoveredLocationsURL, middleware.project.requireProjectAccess);
  app.post(invokeCoveredLocationsURL, middleware.project.requireProjectAvailable);
  app.post(invokeCoveredLocationsURL, getInvokeCoveredLocations);

  // 添加集成函数指针目标
  app.post(integratedFuncsPointerTargetsURL, middleware.user.requireTokenUnexpired);
  app.post(integratedFuncsPointerTargetsURL, middleware.user.requireAvailable);
  app.post(integratedFuncsPointerTargetsURL, middleware.user.requireTester);
  app.post(integratedFuncsPointerTargetsURL, middleware.function.requireFunctionVariablesExist);
  app.post(integratedFuncsPointerTargetsURL, middleware.project.requireProjectAccess);
  app.post(integratedFuncsPointerTargetsURL, middleware.project.requireProjectAvailable);
  app.post(integratedFuncsPointerTargetsURL, addIntegratedFuncPointerTarget);

  // 编辑集成函数指针目标
  app.put(integratedFuncsPointerTargetURL, middleware.user.requireTokenUnexpired);
  app.put(integratedFuncsPointerTargetURL, middleware.user.requireAvailable);
  app.put(integratedFuncsPointerTargetURL, middleware.user.requireTester);
  app.put(integratedFuncsPointerTargetURL, middleware.function.requireFunctionVariablesExist);
  app.put(integratedFuncsPointerTargetURL, middleware.project.requireProjectAccess);
  app.put(integratedFuncsPointerTargetURL, middleware.project.requireProjectAvailable);
  app.put(integratedFuncsPointerTargetURL, editIntegratedFuncPointerTarget);

  // 删除集成函数指针目标
  app.delete(integratedFuncsPointerTargetURL, middleware.user.requireTokenUnexpired);
  app.delete(integratedFuncsPointerTargetURL, middleware.user.requireAvailable);
  app.delete(integratedFuncsPointerTargetURL, middleware.user.requireTester);
  app.delete(integratedFuncsPointerTargetURL, middleware.function.requireFunctionVariablesExist);
  app.delete(integratedFuncsPointerTargetURL, middleware.project.requireProjectAccess);
  app.delete(integratedFuncsPointerTargetURL, middleware.project.requireProjectAvailable);
  app.delete(integratedFuncsPointerTargetURL, removeIntegratedFuncPointerTarget);

  // 添加集成函数参数检查项
  app.post(integratedFuncsOutputURL, middleware.user.requireTokenUnexpired);
  app.post(integratedFuncsOutputURL, middleware.user.requireAvailable);
  app.post(integratedFuncsOutputURL, middleware.user.requireTester);
  app.post(integratedFuncsOutputURL, middleware.function.requireFunctionVariablesExist);
  app.post(integratedFuncsOutputURL, middleware.project.requireProjectAccess);
  app.post(integratedFuncsOutputURL, middleware.project.requireProjectAvailable);
  app.post(integratedFuncsOutputURL, addIntegratedFuncOutput);

  // 取消集成函数参数检查项
  app.delete(integratedFuncsOutputURL, middleware.user.requireTokenUnexpired);
  app.delete(integratedFuncsOutputURL, middleware.user.requireAvailable);
  app.delete(integratedFuncsOutputURL, middleware.user.requireTester);
  app.delete(integratedFuncsOutputURL, middleware.function.requireFunctionVariablesExist);
  app.delete(integratedFuncsOutputURL, middleware.project.requireProjectAccess);
  app.delete(integratedFuncsOutputURL, middleware.project.requireProjectAvailable);
  app.delete(integratedFuncsOutputURL, removeIntegratedFuncOutput);

  // 获取测试用例输入可添加检查项的集成函数
  app.get(integratedFunctionsUrl, middleware.user.requireTokenUnexpired);
  app.get(integratedFunctionsUrl, middleware.user.requireAvailable);
  app.get(integratedFunctionsUrl, middleware.user.requireTester);
  app.get(integratedFunctionsUrl, middleware.function.requireFunctionExist);
  app.get(integratedFunctionsUrl, middleware.project.requireProjectAccess);
  app.get(integratedFunctionsUrl, middleware.project.requireProjectAvailable);
  app.get(integratedFunctionsUrl, getIntegratedFunctions);

  // 更新测试用例输入可添加检查项的集成函数
  app.put(integratedFunctionsUrl, middleware.user.requireTokenUnexpired);
  app.put(integratedFunctionsUrl, middleware.user.requireAvailable);
  app.put(integratedFunctionsUrl, middleware.user.requireTester);
  app.put(integratedFunctionsUrl, middleware.function.requireFunctionExist);
  app.put(integratedFunctionsUrl, middleware.project.requireProjectAccess);
  app.put(integratedFunctionsUrl, middleware.project.requireProjectAvailable);
  app.put(integratedFunctionsUrl, updateIntegratedFunctions);

  // 设置死循环最大执行次数
  app.post(infiniteLoopsUrl, middleware.user.requireTokenUnexpired);
  app.post(infiniteLoopsUrl, middleware.user.requireAvailable);
  app.post(infiniteLoopsUrl, middleware.user.requireTester);
  app.post(infiniteLoopsUrl, middleware.function.requireFunctionExist);
  app.post(infiniteLoopsUrl, middleware.project.requireProjectAccess);
  app.post(infiniteLoopsUrl, middleware.project.requireProjectAvailable);
  app.post(infiniteLoopsUrl, setInfiniteLoopTimes);

  // 设置死循环最大执行次数
  app.get(infiniteLoopsUrl, middleware.user.requireTokenUnexpired);
  app.get(infiniteLoopsUrl, middleware.user.requireAvailable);
  app.get(infiniteLoopsUrl, middleware.user.requireTester);
  app.get(infiniteLoopsUrl, middleware.function.requireFunctionExist);
  app.get(infiniteLoopsUrl, middleware.project.requireProjectAccess);
  app.get(infiniteLoopsUrl, middleware.project.requireProjectAvailable);
  app.get(infiniteLoopsUrl, getInfiniteLoopTimes);
  // 更新自定义全局变量
  app.post(selfDefinedGlobalsUrl, middleware.user.requireTokenUnexpired);
  app.post(selfDefinedGlobalsUrl, middleware.user.requireAvailable);
  app.post(selfDefinedGlobalsUrl, middleware.user.requireTester);
  app.post(selfDefinedGlobalsUrl, middleware.function.requireFunctionExist);
  app.post(selfDefinedGlobalsUrl, middleware.project.requireProjectAccess);
  app.post(selfDefinedGlobalsUrl, middleware.project.requireProjectAvailable);
  app.post(selfDefinedGlobalsUrl, updateSelfDefinedGlobals);
  // 获取函数自定义全局变量
  app.get(getSelfDefinedGlobalsUrl, middleware.user.requireTokenUnexpired);
  app.get(getSelfDefinedGlobalsUrl, middleware.user.requireAvailable);
  app.get(getSelfDefinedGlobalsUrl, middleware.user.requireTester);
  app.get(getSelfDefinedGlobalsUrl, middleware.function.requireFunctionExist);
  app.get(getSelfDefinedGlobalsUrl, middleware.project.requireProjectAccess);
  app.get(getSelfDefinedGlobalsUrl, middleware.project.requireProjectAvailable);
  app.get(getSelfDefinedGlobalsUrl, getSelfDefinedGlobals);

  // 编辑边界变量
  app.post(funcBorderVariableUrl, middleware.user.requireTokenUnexpired);
  app.post(funcBorderVariableUrl, middleware.user.requireAvailable);
  app.post(funcBorderVariableUrl, middleware.user.requireTester);
  app.post(funcBorderVariableUrl, middleware.user.requireTokenUnexpired);
  app.post(funcBorderVariableUrl, middleware.function.requireFunctionExist);
  app.post(funcBorderVariableUrl, updateFuncBorderVariable);
  // 获取边界变量
  app.get(funcBorderVariableUrl, middleware.user.requireTokenUnexpired);
  app.get(funcBorderVariableUrl, middleware.user.requireAvailable);
  app.get(funcBorderVariableUrl, middleware.user.requireTester);
  app.get(funcBorderVariableUrl, middleware.user.requireTokenUnexpired);
  app.get(funcBorderVariableUrl, middleware.function.requireFunctionExist);
  app.get(funcBorderVariableUrl, getFuncBorderVariable);
  // 获取集成测试解决方案
  app.get(integrattionSolutionURL, middleware.user.requireTokenUnexpired);
  app.get(integrattionSolutionURL, middleware.user.requireAvailable);
  app.get(integrattionSolutionURL, middleware.user.requireTester);
  app.get(integrattionSolutionURL, middleware.user.requireTokenUnexpired);
  app.get(integrattionSolutionURL, middleware.function.requireFunctionExist);
  app.get(integrattionSolutionURL, integrationSolution);
  // 更新集成测试解决方案变量文件
  app.put(integrattionSolutionUpdateFileURL, middleware.user.requireTokenUnexpired);
  app.put(integrattionSolutionUpdateFileURL, middleware.user.requireAvailable);
  app.put(integrattionSolutionUpdateFileURL, middleware.user.requireTester);
  app.put(integrattionSolutionUpdateFileURL, middleware.user.requireTokenUnexpired);
  app.put(integrattionSolutionUpdateFileURL, middleware.function.requireFunctionExist);
  app.put(integrattionSolutionUpdateFileURL, integrationSolutionUpdateFile);

  // 手动覆盖
  app.post(manuallyCoverUrl, middleware.user.requireTokenUnexpired);
  app.post(manuallyCoverUrl, middleware.user.requireAvailable);
  app.post(manuallyCoverUrl, middleware.user.requireTester);
  app.post(manuallyCoverUrl, middleware.function.requireFunctionExist);
  app.post(manuallyCoverUrl, middleware.project.requireProjectAccess);
  app.post(manuallyCoverUrl, manuallyCover);
  // 根据测试用例获取函数覆盖率
  app.post(testcaseCoverageUrl, middleware.user.requireTokenUnexpired);
  app.post(testcaseCoverageUrl, middleware.user.requireAvailable);
  app.post(testcaseCoverageUrl, middleware.user.requireTester);
  app.post(testcaseCoverageUrl, middleware.function.requireFunctionExist);
  app.post(testcaseCoverageUrl, middleware.project.requireProjectAccess);
  app.post(testcaseCoverageUrl, getFunctionCoverages);
  // 获取函数及调用覆盖的具体覆盖情况
  app.get(integrationCoveredDetail, middleware.function.requireFunctionExist);
  app.get(integrationCoveredDetail, getIntegrationCoveredDetail);
};
